#include "AC33Mxxx_conf.h"
#include "driver_header.h"
#include "AC33Mxxx_it.h"


int 	g_SPI0_index; 
UINT32	g_SPI0_status[40];

int 	g_SPI1_index; 
UINT32	g_SPI1_status[40]; 


SPI_BUFFER		sSPI0_Master_Buffer; 
SPI_BUFFER		sSPI0_Slave_Buffer; 

SPI_BUFFER		sSPI1_Master_Buffer; 
SPI_BUFFER		sSPI1_Slave_Buffer; 




/**
************************************************************************************************************
* @ Name: SPI_Init
*
* @ Parameter
*		- spi_no : 0, 1
*		- master_slave : SPI_MASTER, SPI_SLAVE
*		- port_sel : SPI_PORTSEL_NORMAL, SPI_PORTSEL_STAR
*
*		- p_config
*			# SS_enable			= SPI_SS_ENABLE, SPI_SS_DISABLE
*			# SS_auto_manual		= SPI_SS_AUTOMATIC, SPI_SS_MANUAL
*			# SS_polarity			= SPI_SS_ACTIVE_HIGH, SPI_SS_ACTIVE_LOW 
*			# SS_masking		= SPI_SS_MASKING, SPI_SS_NOT_MASKING
*
*			# msb_lsb_first		= SPI_MSB_FIRST, SPI_LSB_FIRST
*			# clock_polarity		= SPI_CPOL_ACTIVE_HIGH, SPI_CPOL_ACTIVE_LOW
*			# clock_phase			= SPI_CPHA_FRONT_HALF, SPI_CPHA_REAR_HALF 
*			# bit_size			= SPI_BITSIZE_8_BITS, SPI_BITSIZE_9_BITS, SPI_BITSIZE_16_BITS, SPI_BITSIZE_17_BITS
*
*			# baudrate			= 0x0001 ~ 0xFFFF
*
*			# start_len			= 1 ~ 255
*			# burst_len			= 1 ~ 255
*			# stop_len			= 1 ~ 255
*
*
* @ Return
*		0 = success
*		1 = fail 
*
*
************************************************************************************************************
*/
int SPI_Init (int spi_no, int master_slave, int port_sel, SPI_CONFIG * p_config)
{

	CSP_SPI_T			* spi;
	NVIC_IntrConfig		nvic_config; 
	


	//------------------------------------------------------------------------------------------
	// get object 
	//------------------------------------------------------------------------------------------
	spi = SPI_Get_Object(spi_no); 

	

	//------------------------------------------------------------------------------------------
	// configure GPIO 
	//------------------------------------------------------------------------------------------
	CSP_SPI_ConfigureGPIO(spi, master_slave, port_sel); 
	


	//------------------------------------------------------------------------------------------
	// buffer setting 
	//------------------------------------------------------------------------------------------	
	SPI_InitBuffer (spi_no, master_slave); 


	//------------------------------------------------------------------------------------------
	// mode setting 
	//------------------------------------------------------------------------------------------	
	CSP_SPI_Init (spi, master_slave, p_config); 


	//------------------------------------------------------------------------------------------
	// write dummy data
	//
	//			prevent interrupt from occuring at initialization
	//------------------------------------------------------------------------------------------
	CSP_SPI_SET_SPnTDR(spi, 0x05); 
	

	//------------------------------------------------------------------------------------------
	// interrupt (peripheral) 
	//------------------------------------------------------------------------------------------	
	if (master_slave == SPI_MASTER)
	{
		CSP_SPI_ConfigureInterrupt(spi, SPnCR_TXIE, INTR_ENABLE);
	}
	else if (master_slave == SPI_SLAVE)
	{
		CSP_SPI_ConfigureInterrupt(spi, (SPnCR_SSCIE|SPnCR_TXIE|SPnCR_RXIE), INTR_ENABLE);
	}


	//------------------------------------------------------------------------------------------
	// interrupt (NVIC)
	//------------------------------------------------------------------------------------------		
	nvic_config.nIRQ_Number = (IRQ_SPI0+spi_no); 
	nvic_config.u8Preemption_Priority= PRIO_SPI0_PREEMPTION; 
	nvic_config.u8Subpriority= PRIO_SPI0_SUBPRIORITY; 
	nvic_config.u8IntrEnable = INTR_ENABLE; 
	CSP_NVIC_ConfigureInterrupt (NVIC, &nvic_config); 


	//------------------------------------------------------------------------------------------
	// enable 
	//------------------------------------------------------------------------------------------
	if (master_slave == SPI_SLAVE) CSP_SPI_Enable (spi); 
									

	return (0); 
}



/**
************************************************************************************************************
* @ Name: SPI_Get_Object
*
* @ Parameter
*		- spi_no : 0, 1
*
* @ Return
*		SPI object 
*
*
************************************************************************************************************
*/
CSP_SPI_T* SPI_Get_Object (int spi_no)
{

	CSP_SPI_T * p_obj; 


	switch (spi_no)
	{
	case 0:
		p_obj = SPI0; 
		break; 

	case 1: 
		p_obj = SPI1; 
		break; 

	default: 
		p_obj = (CSP_SPI_T *) 0; 
		break; 
	}


	return (p_obj); 
}


/**
************************************************************************************************************
* @ Name: SPI_InitBuffer
*
* @ Parameter
*		- spi_no : 0, 1
*		- master_slave : SPI_MASTER, SPI_SLAVE
*
* @ Return
*		0 = success
*		1 = fail 
*
*
************************************************************************************************************
*/
int SPI_InitBuffer (int spi_no, int master_slave)
{

	SPI_BUFFER			*p_SPI_buffer; 
	int					i; 
	int					result; 


	//------------------------------------------------------------------------------------------
	// get base address
	//------------------------------------------------------------------------------------------
	p_SPI_buffer = SPI_Get_BufferAddr (spi_no, master_slave, &result); 


	if (result == SPI_CHANNEL_NOT_SUPPORTED)
	{
		return (1);
	}



	//------------------------------------------------------------------------------------------
	// init buffer variables 
	//------------------------------------------------------------------------------------------
	p_SPI_buffer->u16RxState = SPI_RX_STATE_IDLE;
	p_SPI_buffer->u16TxState = SPI_TX_STATE_IDLE;

	p_SPI_buffer->u16RxBuffer_HeadIndex = 0; 
	p_SPI_buffer->u16RxBuffer_TailIndex = 0;
	p_SPI_buffer->u16TxBuffer_HeadIndex = 0; 
	p_SPI_buffer->u16TxBuffer_TailIndex = 0; 

	for (i=0; i<SPI_MAX_RX_BUFFER; i++)
	{
		p_SPI_buffer->u32RxBuffer[i] = 0; 
	}


	for (i=0; i<SPI_MAX_TX_BUFFER; i++)
	{
		p_SPI_buffer->u32TxBuffer[i] = 0; 
	}	


	return (0); 
	
}




/**
************************************************************************************************************
* @ Name: SPI_Get_BufferAddr
*
* @ Parameter
*		- spi_no : 0, 1
*		- master_slave : SPI_MASTER, SPI_SLAVE
*		- *p_result: &result 
*
* @ Return
*		buffer address
*
*
************************************************************************************************************
*/
SPI_BUFFER* SPI_Get_BufferAddr (int spi_no, int master_slave, int *p_result)
{

	SPI_BUFFER		*p_SPI_buffer; 
	int				result = SPI_CHANNEL_SUPPORTED; 


	switch (spi_no)
	{
	case 0:
		if (master_slave == SPI_MASTER) p_SPI_buffer = &sSPI0_Master_Buffer; 
		else if (master_slave == SPI_SLAVE) p_SPI_buffer = &sSPI0_Slave_Buffer; 
		else result = SPI_CHANNEL_NOT_SUPPORTED; 

		break; 

	case 1: 
		if (master_slave == SPI_MASTER) p_SPI_buffer = &sSPI1_Master_Buffer; 
		else if (master_slave == SPI_SLAVE) p_SPI_buffer = &sSPI1_Slave_Buffer; 
		else result = SPI_CHANNEL_NOT_SUPPORTED; 

		break; 

	default:
		result = SPI_CHANNEL_NOT_SUPPORTED; 
		break; 
	}

	*p_result = result; 

	return (p_SPI_buffer); 


}







/**
************************************************************************************************************
* @ Name: SPI_Write_Data
*
* @ Parameter
*		- spi_no : 0, 1
*		- master_slave : SPI_MASTER, SPI_SLAVE
*		- *p_write_buf : &data_buf[n]
*		- data_count: max. 20
*
* @ Return
*		SPI_TX_BUFFER_ERROR_WRONG_CHANNEL 
*		SPI_TX_BUFFER_ERROR_WAIT_TIMEOUT
*
*
************************************************************************************************************
* # How To Use Interrupt-drive SPI Transmission
*
*		1) clear buffer (TXBC) @ main routine --> interrupt is called 
*
*		2) enter first data into SPnTDR @ interrupt routine --> this clears interrupt flag
*
*		3) enable SPI @ main routine --> data in SPnTDR is conveyed into shift register 
*							        --> Now SPnTDR is empty, so another interrupt is called. 
*
*		4) enter next data into SPnTDR --> follow the transmission sequence
*
*
* # Thumb of Rules
*
*		- clear buffer : must be done at main routine
*
*		- enter data : must be done at interrupt routine
*
*		- enable SPI : must be done at main routine
*
*		- disable SPI : must be done at main routine
*
*		==> don't mess up the sequence unless you have sufficient rationale.
*
*
************************************************************************************************************
*/
int SPI_Write_Data (int spi_no, int master_slave, UINT32 *p_write_buf, UINT32 data_count)
{

	SPI_BUFFER			*p_SPI_buffer; 
	CSP_SPI_T			*spi; 
	int					i; 
	int					status;
	//UINT32				data; 


	//------------------------------------------------------------------------------------------
	// get SPI object 
	//------------------------------------------------------------------------------------------
	spi = SPI_Get_Object(spi_no); 
	
	if (spi == (CSP_SPI_T *) 0)
	{
		return (SPI_TX_BUFFER_ERROR_WRONG_CHANNEL);
	}
	


	//------------------------------------------------------------------------------------------
	// get base address
	//------------------------------------------------------------------------------------------
	p_SPI_buffer = SPI_Get_BufferAddr (spi_no, master_slave, &status); 

	if (status == SPI_CHANNEL_NOT_SUPPORTED)
	{
		return (SPI_TX_BUFFER_ERROR_WRONG_CHANNEL);
	}	



	//------------------------------------------------------------------------------------------
	// examine if SPI (TX) is idle
	//------------------------------------------------------------------------------------------
	for (i=0; i<10000; i++)
	{
		if (p_SPI_buffer->u16TxState == SPI_TX_STATE_IDLE) break; 
	}


	if (i == 10000)
	{
		return (SPI_TX_BUFFER_ERROR_WAIT_TIMEOUT); 
	}



	//------------------------------------------------------------------------------------------
	// copy data from write-buffer to SPI-buffer 
	//------------------------------------------------------------------------------------------
	for (i=0; i<data_count; i++)
	{

		p_SPI_buffer->u32TxBuffer[i] = *(p_write_buf + i); 
	}

	p_SPI_buffer->u16TxBuffer_HeadIndex = 0; 
	p_SPI_buffer->u16TxBuffer_TailIndex = data_count; 




	//------------------------------------------------------------------------------------------
	// update state & init SCLK count 
	//------------------------------------------------------------------------------------------
	p_SPI_buffer->u16TxState = SPI_TX_STATE_TRANSMIT; 
	p_SPI_buffer->u16SCLK_count = 0; 



	//------------------------------------------------------------------------------------------
	// start transmission  
	//------------------------------------------------------------------------------------------
	HAL_SPI_LOAD_FIRST_DATA(spi); 

	while(HAL_SPI_IS_FIRST_DATA_NOT_LOADED(spi)); 


	HAL_SPI_ENABLE(spi); 



	return (SPI_TX_BUFFER_SUCCESS); 
	
}




/**
************************************************************************************************************
* @ Name: SPI_Read_Data
*
* @ Parameter
*		- spi_no : 0, 1
*		- master_slave : SPI_MASTER, SPI_SLAVE
*		- *p_read_buf : data buffer to transmit to the counterpart 
*		- p_data_count
*
* @ Return
*		SPI_RX_BUFFER_SUCCESS
*		SPI_RX_BUFFER_ERROR_WRONG_CHANNEL 
*		SPI_RX_BUFFER_ERROR_WAIT_TIMEOUT
*
*
************************************************************************************************************
*/
int SPI_Read_Data (int spi_no, int master_slave, UINT32 * p_read_buf, UINT32 * p_data_count)
{
	CSP_SPI_T		* spi;
	SPI_BUFFER		* p_SPI_buffer; 

	int				i;
	int				status; 
	int				request_count; 
	int				read_count; 


	//------------------------------------------------------------------------------------------
	// get SPI object 
	//------------------------------------------------------------------------------------------
	spi = SPI_Get_Object(spi_no); 

	if (spi == (CSP_SPI_T *) 0)
	{
		return (SPI_RX_BUFFER_ERROR_WRONG_CHANNEL);
	}


	//------------------------------------------------------------------------------------------
	// get base address
	//------------------------------------------------------------------------------------------
	p_SPI_buffer = SPI_Get_BufferAddr (spi_no, master_slave, &status); 

	if (status == SPI_CHANNEL_NOT_SUPPORTED)
	{
		return (SPI_RX_BUFFER_ERROR_WRONG_CHANNEL);
	}	


	//------------------------------------------------------------------------------------------
	// get received data
	//------------------------------------------------------------------------------------------
	request_count = *p_data_count; 
	read_count = 0; 
	
	for (i=0; i<request_count; i++)
	{
		if (p_SPI_buffer->u16RxBuffer_HeadIndex != p_SPI_buffer->u16RxBuffer_TailIndex)
		{
		
			*(p_read_buf + i) = p_SPI_buffer->u32RxBuffer[p_SPI_buffer->u16RxBuffer_HeadIndex++]; 

			if (p_SPI_buffer->u16RxBuffer_HeadIndex >= SPI_MAX_RX_BUFFER) 
				p_SPI_buffer->u16RxBuffer_HeadIndex = 0; 

			read_count++; 
		}
		else
		{
			*(p_read_buf + i) = 0; 
		}
	}


	*p_data_count = read_count; 
	
	return (SPI_RX_BUFFER_SUCCESS); 


}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
************************************************************************************************************
* @ Name: SPI0_Master_Transmit_Receive_ISR
*
* @ Parameter
*		none 
*
* @ Function
*		interrupt handler 
*
************************************************************************************************************
*/
void SPI0_Master_Transmit_Receive_ISR(void)
{

	CSP_SPI_T		* spi = SPI0; 
	SPI_BUFFER		* spi_buffer = &sSPI0_Master_Buffer; 

	UINT32			status, enable; 
	UINT32			send_data, rcv_data; 
	//int			fSSDET = 0, fSSON = 0; 
	int				fTransmit = 0;
	//int			 fReceive = 0; 


	
	//------------------------------------------------------------------------------------------
	// get status & enable 
	//
	//				@ SP0SR = 0x4000_9008
	//				@ SP0EN = 0x4000_9010
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 
	enable = CSP_SPI_GET_SPnEN(spi); 



	//------------------------------------------------------------------------------------------
	// update RX state
	//
	//				TX state is addressed in other routine
	//------------------------------------------------------------------------------------------
	if (status & SPnSR_SSDET)
	{
		if (status & SPnSR_SSON)
			spi_buffer->u16RxState = SPI_RX_STATE_RECEIVE;
		else
			spi_buffer->u16RxState = SPI_RX_STATE_IDLE;
	}

	

	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------
	if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = (status | ((g_SPI0_count & 0xFF)<<24)); 

		

	//======================================================================
	// START 
	//
	//				The purpose of this portion is to enter the first data into SPnTDR. 
	//======================================================================
	if (enable == 0)
	{
		// write first data
		send_data = SPI0_Master_Get_TX_Data_ISR(); 
		if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = send_data; 
		HAL_SPI_WRITE_DATA(spi, send_data); 

		status = CSP_SPI_GET_SPnSR(spi); 
		if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = (status | ((g_SPI0_count & 0xFF)<<24)); 
		
		return; 

	}


	//------------------------------------------------------------------------------------------
	// interrupt service 
	//------------------------------------------------------------------------------------------
	/*
	if (status & SPnSR_SBUSY)
	{

	}

	if (status & SPnSR_SSDET)
	{
		fSSDET = 1; 
	}

	if (status & SPnSR_SSON)
	{
		fSSON = 1;
	}


	if (status & SPnSR_OVRF)
	{

	}


	if (status & SPnSR_UDRF)
	{


	}


	if (status & SPnSR_SRDY)
	{

	}
	*/

	if (status & SPnSR_TRDY)
	{
		fTransmit = 1; 
	}


	if (status & SPnSR_RRDY)
	{
		//fReceive = 1; 
		
		rcv_data = CSP_SPI_GET_SPnRDR(spi); 
		SPI0_Master_Deposit_RX_Data_ISR(rcv_data); 
			

		//-------------------------------------------------------------------------------------
		// The count of SCLKs exactly corresponds to the count of receive-interruts. 
		//-------------------------------------------------------------------------------------
		spi_buffer->u16SCLK_count++; 
	}

	if (fTransmit)
	{
		send_data = SPI0_Master_Get_TX_Data_ISR(); 
		if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = send_data; 
		HAL_SPI_WRITE_DATA(spi, send_data); 

	}


	//------------------------------------------------------------------------------------------
	// get status again 
	//
	//				@ SP0SR = 0x4000_9008
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 


	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------	
	if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = (status | ((g_SPI0_count & 0xFF)<<24));


	//------------------------------------------------------------------------------------------
	// turn off SPI
	//
	//				If all data to be sent are transmitted, turn off the SPI. 
	//------------------------------------------------------------------------------------------
	if(spi_buffer->u16SCLK_count == spi_buffer->u16TxBuffer_TailIndex) 
	{
		spi_buffer->u16TxBuffer_HeadIndex = 0;
		spi_buffer->u16TxBuffer_TailIndex = 0; 
		spi_buffer->u16TxState = SPI_TX_STATE_IDLE; 
		
		HAL_SPI_DISABLE(spi); 
	}
	 



}


/**
************************************************************************************************************
* @ Name: SPI0_Slave_Transmit_Receive_ISR
*
* @ Parameter
*		none 
*
* @ Function
*		interrupt handler 
*
************************************************************************************************************
*/
void SPI0_Slave_Transmit_Receive_ISR (void)
{

	CSP_SPI_T		* spi = SPI0; 
	SPI_BUFFER		* spi_buffer = &sSPI0_Slave_Buffer; 

	UINT32			status;
	//UINT32		 enable; 
	UINT32			send_data, rcv_data; 
	int 			fSSDET = 0, fSSON = 0; 
	int 			fTransmit = 0; 
	// int			fReceive = 0; 


	//------------------------------------------------------------------------------------------
	// get status
	//
	//				@ SP0SR = 0x4000_9008
	//				@ SP0EN = 0x4000_9010
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 
	//enable = CSP_SPI_GET_SPnEN(spi); 



	//------------------------------------------------------------------------------------------
	// update RX state
	//------------------------------------------------------------------------------------------
	if (status & SPnSR_SSDET) 
	{
		if (status & SPnSR_SSON)
		{
			spi_buffer->u16RxState = SPI_RX_STATE_RECEIVE;
			spi_buffer->u16TxState = SPI_TX_STATE_TRANSMIT; 
		}
		else 
		{
			spi_buffer->u16RxState = SPI_RX_STATE_IDLE;
			spi_buffer->u16TxState = SPI_TX_STATE_IDLE; 
		}
	}



	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------
	if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = (status | ((g_SPI0_count & 0xFF)<<24)); 
		


	//------------------------------------------------------------------------------------------
	// interrupt service 
	//------------------------------------------------------------------------------------------
	/*
	if (status & SPnSR_SBUSY)
	{

	}
	*/


	if (status & SPnSR_SSDET) 
	{

		fSSDET = 1; 
		
		status = CSP_SPI_GET_SPnSR(spi); 
		status &= ~SPnSR_SSDET; 
		CSP_SPI_SET_SPnSR(spi, status); 
	}

	if (status & SPnSR_SSON)
	{
		fSSON = 1; 
	}


	if ((fSSDET == 1) && (fSSON == 1))
	{
		//----------------------------------------------------------------------------------
		// If the condition of both "fSSDET == 1" and  "fSSON == 1" is met, the cause of the current 
		// interrupt is SS-detect interrupt at START stage. 
		//
		// Clear buffer and then fill data into SPnTDR. 
		//
		// The first data transmitted is a dummy data. The legitimate data is transmitted from the second SCLK. 
		//----------------------------------------------------------------------------------
		HAL_SPI_BUFFER_CLEAR(spi); 

		send_data = SPI0_Slave_Get_TX_Data_ISR(); 
		HAL_SPI_WRITE_DATA(spi, send_data);  
			

		//----------------------------------------------------------------------------------
		// Update status by reading SPnSR register.
		//
		// This step will clear the TRDY bit, which prevent this routine from loading TX data one more time
		// at the current interrupt service routine (consult "fTransmit" step.)
		//----------------------------------------------------------------------------------
		status = CSP_SPI_GET_SPnSR(spi); 
		if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = (status | ((g_SPI0_count & 0xFF)<<24));	
	}


	if (status & SPnSR_OVRF)
	{

	}


	if (status & SPnSR_UDRF)
	{
		CSP_SPI_SET_SPnTDR(spi, 0); 
		status = CSP_SPI_GET_SPnSR(spi); 

	}


	if (status & SPnSR_SRDY)
	{

	}


	if (status & SPnSR_TRDY)
	{
		fTransmit = 1; 
	}


	if (status & SPnSR_RRDY)
	{

		//fReceive = 1; 
		
		rcv_data = CSP_SPI_GET_SPnRDR(spi); 
		SPI0_Slave_Deposit_RX_Data_ISR (rcv_data); 
		

	}


	//----------------------------------------------------------------------------------
	// Because SPnEN is always set if the SPI module is used as slave, TRDY interrupt will be called
	// after transmitting all legitimate data. 
	//
	// In such case, dummy data will be entered into TDR to prevent further interrupts.
	//----------------------------------------------------------------------------------
	if (fTransmit)
	{

		send_data = SPI0_Slave_Get_TX_Data_ISR(); 
		HAL_SPI_WRITE_DATA(spi, send_data);  
		
	}


	//------------------------------------------------------------------------------------------
	// get status again 
	//
	//				@ SP0SR = 0x4000_9008
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 


	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------
	if (g_SPI0_index < 40) g_SPI0_status[g_SPI0_index++] = (status | ((g_SPI0_count & 0xFF)<<24));	


}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/**
************************************************************************************************************
* @ Name: SPI1_Master_Transmit_Receive_ISR
*
* @ Parameter
*		none 
*
* @ Function
*		interrupt handler 
*
************************************************************************************************************
*/
void SPI1_Master_Transmit_Receive_ISR (void)
{

	CSP_SPI_T		* spi = SPI1; 
	SPI_BUFFER		* spi_buffer = &sSPI1_Master_Buffer; 

	UINT32			status; 
	UINT32			enable; 
	UINT32			send_data, rcv_data; 
	//int 			fSSDET = 0, fSSON = 0; 
	int 			fTransmit = 0; 
	// int			fReceive = 0; 



	//------------------------------------------------------------------------------------------
	// get status & enable 
	//
	//				@ SP1SR = 0x4000_9108
	//				@ SP1EN = 0x4000_9110
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 
	enable = CSP_SPI_GET_SPnEN(spi); 



	//------------------------------------------------------------------------------------------
	// update RX state
	//
	//				TX state is addressed in other routine
	//------------------------------------------------------------------------------------------
	if (status & SPnSR_SSDET)
	{
		if (status & SPnSR_SSON)
			spi_buffer->u16RxState = SPI_RX_STATE_RECEIVE;
		else
			spi_buffer->u16RxState = SPI_RX_STATE_IDLE;
	}



	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------
	if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = (status | ((g_SPI1_count & 0xFF)<<24)); 

		

	//======================================================================
	// START 
	//
	//				The purpose of this portion is to enter the first data into SPnTDR. 
	//======================================================================
	if (enable == 0)
	{
		// write first data
		send_data = SPI1_Master_Get_TX_Data_ISR(); 
		if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = send_data; 
		HAL_SPI_WRITE_DATA(spi, send_data); 

		status = CSP_SPI_GET_SPnSR(spi); 
		if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = (status | ((g_SPI1_count & 0xFF)<<24)); 
		
		return; 

	}


	//------------------------------------------------------------------------------------------
	// interrupt service 
	//------------------------------------------------------------------------------------------
	/*
	if (status & SPnSR_SBUSY)
	{

	}

	if (status & SPnSR_SSDET)
	{
		fSSDET = 1; 
	}

	if (status & SPnSR_SSON)
	{
		fSSON = 1;
	}


	if (status & SPnSR_OVRF)
	{

	}


	if (status & SPnSR_UDRF)
	{


	}


	if (status & SPnSR_SRDY)
	{

	}
	*/


	if (status & SPnSR_TRDY)
	{
		fTransmit = 1; 
	}


	if (status & SPnSR_RRDY)
	{
		//fReceive = 1; 
		
		rcv_data = CSP_SPI_GET_SPnRDR(spi); 
		SPI1_Master_Deposit_RX_Data_ISR(rcv_data); 
			

		//-------------------------------------------------------------------------------------
		// The count of SCLKs exactly corresponds to the count of receive-interruts. 
		//-------------------------------------------------------------------------------------
		spi_buffer->u16SCLK_count++; 
	}

	if (fTransmit)
	{
		send_data = SPI1_Master_Get_TX_Data_ISR(); 
		if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = send_data; 
		HAL_SPI_WRITE_DATA(spi, send_data); 

	}


	//------------------------------------------------------------------------------------------
	// get status again 
	//
	//				@ SP1SR = 0x4000_9108
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 


	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------	
	if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = (status | ((g_SPI1_count & 0xFF)<<24));


	//------------------------------------------------------------------------------------------
	// turn off SPI
	//
	//				If all data to be sent are transmitted, turn off the SPI. 
	//------------------------------------------------------------------------------------------
	if(spi_buffer->u16SCLK_count == spi_buffer->u16TxBuffer_TailIndex) 
	{
		spi_buffer->u16TxBuffer_HeadIndex = 0;
		spi_buffer->u16TxBuffer_TailIndex = 0; 
		spi_buffer->u16TxState = SPI_TX_STATE_IDLE; 
		
		HAL_SPI_DISABLE(spi); 
	}


}


/**
************************************************************************************************************
* @ Name: SPI1_Slave_Transmit_Receive_ISR
*
* @ Parameter
*		none 
*
* @ Function
*		interrupt handler 
*
************************************************************************************************************
*/
void SPI1_Slave_Transmit_Receive_ISR (void)
{

	CSP_SPI_T		* spi = SPI1; 
	SPI_BUFFER		* spi_buffer = &sSPI1_Slave_Buffer; 
	
	UINT32			status; 
	// UINT32		 enable; 
	UINT32			send_data, rcv_data; 
	int				fSSDET = 0, fSSON = 0; 
	int				fTransmit = 0; 
	// int			fReceive = 0; 

	
	//------------------------------------------------------------------------------------------
	// get status
	//
	//				@ SP1SR = 0x4000_9108
	//				@ SP1EN = 0x4000_9110
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 
	//enable = CSP_SPI_GET_SPnEN(spi); 



	//------------------------------------------------------------------------------------------
	// update RX state
	//------------------------------------------------------------------------------------------
	if (status & SPnSR_SSDET) 
	{
		if (status & SPnSR_SSON)
		{
			spi_buffer->u16RxState = SPI_RX_STATE_RECEIVE;
			spi_buffer->u16TxState = SPI_TX_STATE_TRANSMIT; 
		}
		else 
		{
			spi_buffer->u16RxState = SPI_RX_STATE_IDLE;
			spi_buffer->u16TxState = SPI_TX_STATE_IDLE; 
		}
	}



	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------
	if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = (status | ((g_SPI1_count & 0xFF)<<24)); 
		


	//------------------------------------------------------------------------------------------
	// interrupt service 
	//------------------------------------------------------------------------------------------
	if (status & SPnSR_SBUSY)
	{

	}
	

	if (status & SPnSR_SSDET) 
	{

		fSSDET = 1; 
		
		status = CSP_SPI_GET_SPnSR(spi); 
		status &= ~SPnSR_SSDET; 
		CSP_SPI_SET_SPnSR(spi, status); 
	}

	if (status & SPnSR_SSON)
	{
		fSSON = 1; 
	}

	
	if ((fSSDET == 1) && (fSSON == 1))
	{
		//----------------------------------------------------------------------------------
		// If the condition of both "fSSDET == 1" and  "fSSON == 1" is met, the cause of the current 
		// interrupt is SS-detect interrupt at START stage. 
		//
		// Clear buffer and then fill data into SPnTDR. 
		//
		// The first data transmitted is a dummy data. The legitimate data is transmitted from the second SCLK. 
		//----------------------------------------------------------------------------------
		HAL_SPI_BUFFER_CLEAR(spi); 

		send_data = SPI1_Slave_Get_TX_Data_ISR(); 
		HAL_SPI_WRITE_DATA(spi, send_data);  
			

		//----------------------------------------------------------------------------------
		// Update status by reading SPnSR register.
		//
		// This step will clear the TRDY bit, which prevent this routine from loading TX data one more time
		// at the current interrupt service routine (consult "fTransmit" step.)
		//----------------------------------------------------------------------------------
		status = CSP_SPI_GET_SPnSR(spi); 
		if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = (status | ((g_SPI1_count & 0xFF)<<24)); 	
	}


	if (status & SPnSR_OVRF)
	{

	}


	if (status & SPnSR_UDRF)
	{
		CSP_SPI_SET_SPnTDR(spi, 0); 
		status = CSP_SPI_GET_SPnSR(spi); 

	}


	if (status & SPnSR_SRDY)
	{

	}


	if (status & SPnSR_TRDY)
	{
		fTransmit = 1; 
	}


	if (status & SPnSR_RRDY)
	{
	
		//fReceive = 1; 
		
		rcv_data = CSP_SPI_GET_SPnRDR(spi); 
		SPI1_Slave_Deposit_RX_Data_ISR (rcv_data); 
		

	}


	//----------------------------------------------------------------------------------
	// Because SPnEN is always set if the SPI module is used as slave, TRDY interrupt will be called
	// after transmitting all legitimate data. 
	//
	// In such case, dummy data will be entered into TDR to prevent further interrupts.
	//----------------------------------------------------------------------------------
	if (fTransmit)
	{

		send_data = SPI1_Slave_Get_TX_Data_ISR(); 
		HAL_SPI_WRITE_DATA(spi, send_data);  
		
	}


	//------------------------------------------------------------------------------------------
	// get status again 
	//
	//				@ SP1SR = 0x4000_9108
	//------------------------------------------------------------------------------------------
	status = CSP_SPI_GET_SPnSR(spi); 


	//------------------------------------------------------------------------------------------
	// monitor 
	//------------------------------------------------------------------------------------------
	if (g_SPI1_index < 40) g_SPI1_status[g_SPI1_index++] = (status | ((g_SPI1_count & 0xFF)<<24)); 	



}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/**
************************************************************************************************************
* @ Name: SPI0_Master_Get_TX_Data_ISR
*
* @ Parameter
*		none
*
* @ Return 
*		TX data 
*
* @ Function
*		interrupt service routine for master  
*
************************************************************************************************************
*/
UINT32 SPI0_Master_Get_TX_Data_ISR (void)
{
	SPI_BUFFER		*p_SPI_buffer = &sSPI0_Master_Buffer; 

	UINT32			send_data; 

	if (p_SPI_buffer->u16TxBuffer_HeadIndex < p_SPI_buffer->u16TxBuffer_TailIndex)
	{
		send_data = p_SPI_buffer->u32TxBuffer[p_SPI_buffer->u16TxBuffer_HeadIndex++]; 
	}
	else
	{
		send_data = SPI_TXDATA_END_MARK; 
	}

	return (send_data);  

}



/**
************************************************************************************************************
* @ Name: SPI0_Master_Deposit_RX_Data_ISR
*
* @ Parameter
*		rcv_data	: 32-bit SPI RX data
*
* @ Function
*		interrupt service routine for master 
*
************************************************************************************************************
*/
void SPI0_Master_Deposit_RX_Data_ISR (UINT32 rcv_data)
{

	SPI_BUFFER		*p_SPI_buffer = &sSPI0_Master_Buffer; 
	UINT32			next_index; 

	
	//------------------------------------------------------------------------------------------
	// search location to deposit data 
	//------------------------------------------------------------------------------------------
	next_index = p_SPI_buffer->u16RxBuffer_TailIndex + 1; 

	if (next_index >= SPI_MAX_RX_BUFFER)
	{
		next_index = 0; 
	}


	//------------------------------------------------------------------------------------------
	// deposit data if space is available 
	//------------------------------------------------------------------------------------------
	if (next_index != p_SPI_buffer->u16RxBuffer_HeadIndex)
	{
		p_SPI_buffer->u32RxBuffer[p_SPI_buffer->u16RxBuffer_TailIndex] = rcv_data; 
		p_SPI_buffer->u16RxBuffer_TailIndex = next_index; 
	}

		

}



/**
************************************************************************************************************
* @ Name: SPI0_Slave_Get_TX_Data_ISR
*
* @ Parameter
*		none 
*
* @ Return 
*		TX data 
*
* @ Function
*		interrupt service routine for master 
*
************************************************************************************************************
*/
UINT32 SPI0_Slave_Get_TX_Data_ISR (void)
{

	SPI_BUFFER		*p_SPI_buffer = &sSPI0_Slave_Buffer; 
	UINT32			send_data; 



	if (p_SPI_buffer->u16TxBuffer_HeadIndex < p_SPI_buffer->u16TxBuffer_TailIndex)
	{
		send_data = p_SPI_buffer->u32TxBuffer[p_SPI_buffer->u16TxBuffer_HeadIndex++]; 
	}
	else
	{
		send_data = SPI_TXDATA_END_MARK; 
	}

	return (send_data); 
	

}



/**
************************************************************************************************************
* @ Name: SPI0_Slave_Deposit_RX_Data_ISR
*
* @ Parameter
*		rcv_data	: 32-bit SPI RX data
*
* @ Function
*		interrupt service routine for master 
*
************************************************************************************************************
*/
void SPI0_Slave_Deposit_RX_Data_ISR (UINT32 rcv_data)
{

	SPI_BUFFER		* p_SPI_buffer = &sSPI0_Slave_Buffer; 
	UINT16			next_index; 



	//------------------------------------------------------------------------------------------
	// search location to deposit data 
	//------------------------------------------------------------------------------------------
	next_index = p_SPI_buffer->u16RxBuffer_TailIndex + 1; 

	if (next_index >= SPI_MAX_RX_BUFFER)
	{
		next_index = 0; 
	}


	//------------------------------------------------------------------------------------------
	// deposit data if space is available 
	//------------------------------------------------------------------------------------------
	if (next_index != p_SPI_buffer->u16RxBuffer_HeadIndex)
	{
		p_SPI_buffer->u32RxBuffer[p_SPI_buffer->u16RxBuffer_TailIndex] = rcv_data; 
		p_SPI_buffer->u16RxBuffer_TailIndex = next_index; 
	}

}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/**
************************************************************************************************************
* @ Name: SPI1_Master_Get_TX_Data_ISR
*
* @ Parameter
*		none
*
* @ Return 
*		TX data 
*
* @ Function
*		interrupt service routine for master  
*
************************************************************************************************************
*/
UINT32 SPI1_Master_Get_TX_Data_ISR (void) 
{

	SPI_BUFFER		*p_SPI_buffer = &sSPI1_Master_Buffer; 

	UINT32			send_data; 

	if (p_SPI_buffer->u16TxBuffer_HeadIndex < p_SPI_buffer->u16TxBuffer_TailIndex)
	{
		send_data = p_SPI_buffer->u32TxBuffer[p_SPI_buffer->u16TxBuffer_HeadIndex++]; 
	}
	else
	{
		send_data = SPI_TXDATA_END_MARK; 
	}

	return (send_data);  


}




/**
************************************************************************************************************
* @ Name: SPI1_Master_Deposit_RX_Data_ISR
*
* @ Parameter
*		rcv_data	: 32-bit SPI RX data
*
* @ Function
*		interrupt service routine for master 
*
************************************************************************************************************
*/
void SPI1_Master_Deposit_RX_Data_ISR (UINT32 rcv_data)
{

	SPI_BUFFER		*p_SPI_buffer = &sSPI1_Master_Buffer; 
	UINT32			next_index; 


	//------------------------------------------------------------------------------------------
	// search location to deposit data 
	//------------------------------------------------------------------------------------------
	next_index = p_SPI_buffer->u16RxBuffer_TailIndex + 1; 

	if (next_index >= SPI_MAX_RX_BUFFER)
	{
		next_index = 0; 
	}


	//------------------------------------------------------------------------------------------
	// deposit data if space is available 
	//------------------------------------------------------------------------------------------
	if (next_index != p_SPI_buffer->u16RxBuffer_HeadIndex)
	{
		p_SPI_buffer->u32RxBuffer[p_SPI_buffer->u16RxBuffer_TailIndex] = rcv_data; 
		p_SPI_buffer->u16RxBuffer_TailIndex = next_index; 
	}


}



/**
************************************************************************************************************
* @ Name: SPI1_Slave_Get_TX_Data_ISR
*
* @ Parameter
*		none
*
* @ Return 
*		TX data 
*
* @ Function
*		interrupt service routine for slave 
*
************************************************************************************************************
*/
UINT32 SPI1_Slave_Get_TX_Data_ISR (void)
{
	SPI_BUFFER		*p_SPI_buffer = &sSPI1_Slave_Buffer; 
	UINT32			send_data; 



	if (p_SPI_buffer->u16TxBuffer_HeadIndex < p_SPI_buffer->u16TxBuffer_TailIndex)
	{
		send_data = p_SPI_buffer->u32TxBuffer[p_SPI_buffer->u16TxBuffer_HeadIndex++]; 
	}
	else
	{
		send_data = SPI_TXDATA_END_MARK; 
	}

	return (send_data);  

}




/**
************************************************************************************************************
* @ Name: SPI1_Slave_Deposit_RX_Data_ISR
*
* @ Parameter
*		rcv_data	: 32-bit SPI RX data
*
* @ Function
*		interrupt service routine for slave 
*
************************************************************************************************************
*/
void SPI1_Slave_Deposit_RX_Data_ISR (UINT32 rcv_data)
{
	SPI_BUFFER		* p_SPI_buffer = &sSPI1_Slave_Buffer; 
	UINT16			next_index; 



	//------------------------------------------------------------------------------------------
	// search location to deposit data 
	//------------------------------------------------------------------------------------------
	next_index = p_SPI_buffer->u16RxBuffer_TailIndex + 1; 

	if (next_index >= SPI_MAX_RX_BUFFER)
	{
		next_index = 0; 
	}


	//------------------------------------------------------------------------------------------
	// deposit data if space is available 
	//------------------------------------------------------------------------------------------
	if (next_index != p_SPI_buffer->u16RxBuffer_HeadIndex)
	{
		p_SPI_buffer->u32RxBuffer[p_SPI_buffer->u16RxBuffer_TailIndex] = rcv_data; 
		p_SPI_buffer->u16RxBuffer_TailIndex = next_index; 
	}


}






